package com.xuhe.server.service.impl;

import com.xuhe.server.domain.db1.dao.gp.AnalysisMapper;
import com.xuhe.server.domain.db1.dao.gp.BuysMapper;
import com.xuhe.server.domain.db1.dao.gp.GpMapper;
import com.xuhe.server.domain.db1.dao.gp.HistoryMapper;
import com.xuhe.server.domain.db1.dataobject.gp.Analysis;
import com.xuhe.server.domain.db1.dataobject.gp.Buys;
import com.xuhe.server.domain.db1.dataobject.gp.History;
import com.xuhe.server.service.AnalysisService;
import com.yszn.base.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Service
public class AnalysisServiceImpl implements AnalysisService {
    @Autowired
    private GpMapper gpMapper;

    @Autowired
    private HistoryMapper historyMapper;

    @Autowired
    private AnalysisMapper analysisMapper;

    @Autowired
    private BuysMapper buysMapper;

    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    private static final Integer threadMax = 50;

    @Override
    public void guessBuys(String start, String end, Integer limit) {
        List<String> codeList = historyMapper.findAllZtCode(start, end);
        log.info("标的总数：{}，区间：{} - {}，开始分析...... ", codeList.size(), start, end);

        buysMapper.deleteAll(end);

        List<History> buys = new ArrayList<>();
        List<History> attentions = new ArrayList<>();
        AtomicInteger index = new AtomicInteger(0);
        int range = 1 + (codeList.size() / threadMax);
        List<Future<String>> threadList = new ArrayList<>();
        for (int rangI = 0; rangI < threadMax; rangI ++){
            int finalI = rangI;
            Future<String> future = taskExecutor.submit(() -> {
                int st = finalI * range;
                int max = range * (finalI + 1);
                if (max > codeList.size()) max = codeList.size();
                for (int j = st; j < max; j ++) {
                    String code = codeList.get(j);
                    List<History> days = new ArrayList<>(); // 分析数据缓存

                    List<History> list = historyMapper.findListByDateAndLimit(code, start, end);
                    for (History history : list) {
                        if (analysisModel(history, days, limit)) {
                            if (history.getDate().equals(end)) {
                                log.info("尾盘买入：{}", history);
                                Buys b = new Buys();
                                BeanUtils.copyProperties(history, b);
                                b.setResType("买入");
                                b.setResDate(end);
                                buysMapper.insert(b);
                                buys.add(history);
                            } else {
//                                log.info("尾盘关注：{}", history);
//                                Buys b = new Buys();
//                                BeanUtils.copyProperties(history, b);
//                                b.setResType("关注");
//                                b.setResDate(DateUtil.dateToOnlyDateString(new Date()));
//                                buysMapper.insert(b);
//                                attentions.add(history);
                            }
                        }
                    }
                    index.set(index.get() + 1);
                    log.info("已分析：{}个，进度：{}%", index.get(), (double) (index.get() * 1000 / codeList.size()) / 10);
                }
                return "线程" + finalI + "执行结束";
            });
            threadList.add(future);
        }
        for (Future<String> future : threadList) {
            try {
                log.info("{}", future.get());
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            }
        }


//        int mod = codeList.size()/30;
//        int range = mod == 1? 1 : mod - 1;
//
//        Thread[] threads = new Thread[1 + (codeList.size()/range)];
//
//        for (int rangI = 0; rangI < 1 + codeList.size()/range; rangI ++){
//            int finalI = rangI;
//            threads[rangI] = new Thread(() -> {
//                int st = finalI * range;
//                int max = range * (finalI + 1);
//                if (max > codeList.size()) max = codeList.size();
//                for (int j = st; j < max; j ++){
//                    String code = codeList.get(j);
//                    List<History> days = new ArrayList<>(); // 分析数据缓存
//
//                    List<History> list = historyMapper.findListByDateAndLimit(code, start, end);
//                    for (History history : list) {
//                        if (analysisModel(history, days, limit)) {
//                            if (history.getDate().equals(end)) {
//                                log.info("买入：{}", history);
//                                Buys b = new Buys();
//                                BeanUtils.copyProperties(history, b);
//                                buysMapper.insert(b);
//                                buys.add(history);
//                            } else {
//                                log.info("关注：{}", history);
//                                attentions.add(history);
//                            }
//                        }
//                    }
//                    index.set(index.get() + 1);
//                    log.info("已分析：{}个，进度：{}%", index.get(), (double)(index.get() * 1000/codeList.size())/10);
//                }
//            });
//        }
//
//        for (Thread thread : threads) {
//            thread.start();
//        }
//        for (Thread thread : threads) {
//            try {
//                thread.join();
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
//        }

        log.info("分析完成，结果如下：");
        for (History buy : buys) {
            log.info("买入：{}", buy);
        }
        for (History attention : attentions) {
            log.info("关注：{}", attention);
        }
    }

    @Override
    public void analysisByCode(String code, String start, String end, Integer limit) {
        List<History> buys = new ArrayList<>(); // 前一天尾盘买入
        List<History> days = new ArrayList<>(); // 分析数据缓存

        List<History> list = historyMapper.findListByDateAndLimit(code, start, end);
        boolean isBuy = false; // 第一天
        for (History history : list) {
            if (isBuy && buys.size() < 7) {
                buys.add(history);
                continue;
            }else if (buys.size() > 0){
                BigDecimal total = new BigDecimal(0);
                for (History buy : buys) {
                    Analysis analysis = new Analysis();
                    total = total.add(new BigDecimal(buy.getRatio().replace("%", "")));
                    BeanUtils.copyProperties(buy, analysis);
                    analysis.setTotalRatio(total.setScale(2, RoundingMode.HALF_UP) + "%");
                    analysisMapper.insert(analysis);
                }
                buys.clear();
            }

            isBuy = analysisModel(history, days, limit);
        }
        if (buys.size() > 0) {
            BigDecimal total = new BigDecimal(0);
            for (History buy : buys) {
                Analysis analysis = new Analysis();
                total = total.add(new BigDecimal(buy.getRatio().replace("%", "")));
                BeanUtils.copyProperties(buy, analysis);
                analysis.setTotalRatio(total.setScale(2, RoundingMode.HALF_UP) + "%");
                analysisMapper.insert(analysis);
            }
        }
    }

    @Override
    public void analysisAll(String start, String end, Integer limit) {
        List<String> codeList = historyMapper.findAllZtCode(start, end);
        log.info("标的总数：{}，区间：{} - {}，开始分析...... ", codeList.size(), start, end);

        analysisMapper.deleteAll();
        AtomicInteger index = new AtomicInteger(0);
        int range = 1 + (codeList.size() / threadMax);

        List<Future<String>> threadList = new ArrayList<>();
        for (int threadIndex = 0; threadIndex < threadMax; threadIndex ++){
            int finalThreadIndex = threadIndex;
            Future<String> future = taskExecutor.submit(() -> {
                int startIndex = finalThreadIndex * range;
                int endIndex = (finalThreadIndex + 1) * range;
                if (endIndex > codeList.size()) endIndex = codeList.size();
                for (int codeIndex = startIndex; codeIndex < endIndex; codeIndex ++){
                    String c = codeList.get(codeIndex);
                    this.analysisByCode(c, start, end, limit);
                    index.set(index.get() + 1);
                    log.info("已分析：{}个，进度：{}%", index.get(), (double)(index.get() * 1000/codeList.size())/10);
                }
                return "线程" + finalThreadIndex + "执行结束";
            });
            threadList.add(future);
        }
        for (Future<String> future : threadList) {
            try {
                log.info("{}", future.get());
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            }
        }
        log.info("已分析完成");
        statAnalysisResult(codeList.size(), start, end);
    }

    @Override
    public void statAnalysisResult(Integer count, String start, String end) {
        List<Analysis> list = analysisMapper.findAll(null);
        log.info("开始统计分析结果...");
        int suc1 = 0;
        int fai1 = 0;
        int zt1 = 0;
        String max1 = "-20%";
        String min1 = "20%";
        double sy1 = 0;
        double dtsy1 = 0;

        int suc2 = 0;
        int fai2 = 0;
        int zt2 = 0;
        String max2 = "-20%";
        String min2 = "20%";
        double sy2 = 0;
        double dtsy2 = 0;

        int suc3 = 0;
        int fai3 = 0;
        int zt3 = 0;
        String max3 = "-20%";
        String min3 = "20%";
        double sy3 = 0;
        double dtsy3 = 0;

        int suc4 = 0;
        int fai4= 0;
        int zt4 = 0;
        String max4 = "-20%";
        String min4 = "20%";
        double sy4 = 0;
        double dtsy4 = 0;

        int suc5 = 0;
        int fai5= 0;
        int zt5 = 0;
        String max5 = "-20%";
        String min5 = "20%";
        double sy5 = 0;
        double dtsy5 = 0;

        int suc6 = 0;
        int fai6= 0;
        int zt6 = 0;
        String max6 = "-20%";
        String min6 = "20%";
        double sy6 = 0;
        double dtsy6= 0;

        int suc7 = 0;
        int fai7= 0;
        int zt7 = 0;
        String max7 = "-20%";
        String min7 = "20%";
        double sy7 = 0;
        double dtsy7 = 0;

        String code = null;
        boolean day1 = false;
        boolean day2 = false;
        boolean day3 = false;
        boolean day4 = false;
        boolean day5 = false;
        boolean day6 = false;
        boolean day7 = false;

        boolean dtday1 = false;
        boolean dtday2 = false;
        boolean dtday3 = false;
        boolean dtday4 = false;
        boolean dtday5 = false;
        boolean dtday6 = false;
        boolean dtday7 = false;

        boolean yxday1 = false;
        boolean yxday2 = false;
        boolean yxday3 = false;
        boolean yxday4 = false;
        boolean yxday5 = false;
        boolean yxday6 = false;
        boolean yxday7 = false;
        double dtsy = 0; // 动态收益
        double ljsy = 0; // 累计收益
        double yxsy = 0; // 阳线收益

        for (Analysis buy : list) {
            // 重置单股周期
            double zf = Double.parseDouble(buy.getRatio().replace("%", ""));
            if (code != null && code.equals(buy.getCode()) && day7) {
                code = null;
            }

            // 统计首日买入结果
            if (code == null || !code.equals(buy.getCode())) {
                if (zf > 0) {
                    suc1 ++;
                    dtday1 = true;
                }else {
                    fai1 ++;
                    dtday1 = false;
                }
                dtday2 = false;
                dtday3 = false;
                dtday4 = false;
                dtday5 = false;
                dtday6 = false;
                dtday7 = false;

                if (Double.parseDouble(buy.getClose()) >= Double.parseDouble(buy.getOpen())) {
                    yxday1 = true;
                }
                yxday2 = false;
                yxday3 = false;
                yxday4 = false;
                yxday5 = false;
                yxday6 = false;
                yxday7 = false;

                sy1 = sy1 + zf;
                ljsy = ljsy + zf;
                dtsy = dtsy + zf;
                yxsy = yxsy + zf;
                if (isZt(buy)) zt1 ++;
                code = buy.getCode();
                if ( Double.parseDouble(buy.getRatio().replace("%", "")) > Double.parseDouble(max1.replace("%", ""))) max1 = buy.getRatio();
                if ( Double.parseDouble(buy.getRatio().replace("%", "")) < Double.parseDouble(min1.replace("%", ""))) min1 = buy.getRatio();

                day1 = true;
                day2 = false;
                day3 = false;
                day4 = false;
                day5 = false;
                day6 = false;
                day7 = false;
            } else if (day1 && code.equals(buy.getCode())) {
                if (zf > 0) {
                    suc2 ++;
                    dtday2 = true;
                }else {
                    fai2 ++;
                    dtday2 = false;
                }

                if (Double.parseDouble(buy.getClose()) >= Double.parseDouble(buy.getOpen())) {
                    yxday2 = true;
                }
                if (yxday1) yxsy = yxsy + zf;

                if (dtday1)  dtsy = dtsy + zf;
                sy2 = sy2 + zf;
                ljsy = ljsy + zf;
                if (isZt(buy)) zt2 ++;
                if ( Double.parseDouble(buy.getRatio().replace("%", "")) > Double.parseDouble(max2.replace("%", ""))) max2 = buy.getRatio();
                if ( Double.parseDouble(buy.getRatio().replace("%", "")) < Double.parseDouble(min2.replace("%", ""))) min2 = buy.getRatio();

                day1 = false;
                day2 = true;
                day3 = false;
                day4 = false;
                day5 = false;
                day6 = false;
                day7 = false;
            } else if (day2 && code.equals(buy.getCode())) {
                if (zf > 0) {
                    suc3 ++;
                    dtday3 = true;
                }else {
                    fai3 ++;
                    dtday3 = false;
                }
                if (Double.parseDouble(buy.getClose()) >= Double.parseDouble(buy.getOpen())) {
                    yxday3 = true;
                }
                if (yxday2) yxsy = yxsy + zf;
                if (dtday2)   dtsy = dtsy + zf;
                sy3 = sy3 + zf;
                ljsy = ljsy + zf;
                if (isZt(buy)) zt3 ++;
                if ( Double.parseDouble(buy.getRatio().replace("%", "")) > Double.parseDouble(max3.replace("%", ""))) max3 = buy.getRatio();
                if ( Double.parseDouble(buy.getRatio().replace("%", "")) < Double.parseDouble(min3.replace("%", ""))) min3 = buy.getRatio();

                day1 = false;
                day2 = false;
                day3 = true;
                day4 = false;
                day5 = false;
                day6 = false;
                day7 = false;
            } else if (day3 && code.equals(buy.getCode())) {
                if (zf > 0) {
                    suc4 ++;
                    dtday4 = true;
                }else {
                    fai4 ++;
                    dtday4 = false;
                }
                if (Double.parseDouble(buy.getClose()) >= Double.parseDouble(buy.getOpen())) {
                    yxday4 = true;
                }
                if (yxday3) yxsy = yxsy + zf;
                if (dtday3)   dtsy = dtsy + zf;
                sy4 = sy4 + zf;
                ljsy = ljsy + zf;
                if (isZt(buy)) zt4 ++;
                if ( Double.parseDouble(buy.getRatio().replace("%", "")) > Double.parseDouble(max4.replace("%", ""))) max4 = buy.getRatio();
                if ( Double.parseDouble(buy.getRatio().replace("%", "")) < Double.parseDouble(min4.replace("%", ""))) min4 = buy.getRatio();

                day1 = false;
                day2 = false;
                day3 = false;
                day4 = true;
                day5 = false;
                day6 = false;
                day7 = false;
            } else if (day4 && code.equals(buy.getCode())) {
                if (zf > 0) {
                    suc5 ++;
                    dtday5 = true;
                }else {
                    fai5 ++;
                    dtday5 = false;
                }
                if (Double.parseDouble(buy.getClose()) >= Double.parseDouble(buy.getOpen())) {
                    yxday5 = true;
                }
                if (yxday4) yxsy = yxsy + zf;
                if (dtday4)   dtsy = dtsy + zf;
                sy5 = sy5 + zf;
                ljsy = ljsy + zf;
                if (isZt(buy)) zt5 ++;
                if ( Double.parseDouble(buy.getRatio().replace("%", "")) > Double.parseDouble(max5.replace("%", ""))) max5 = buy.getRatio();
                if ( Double.parseDouble(buy.getRatio().replace("%", "")) < Double.parseDouble(min5.replace("%", ""))) min5 = buy.getRatio();

                day1 = false;
                day2 = false;
                day3 = false;
                day4 = false;
                day5 = true;
                day6 = false;
                day7 = false;
            } else if (day5 && code.equals(buy.getCode())) {
                if (zf > 0) {
                    suc6 ++;
                    dtday6 = true;
                }else {
                    fai6 ++;
                    dtday6 = false;
                }
                if (Double.parseDouble(buy.getClose()) >= Double.parseDouble(buy.getOpen())) {
                    yxday6 = true;
                }
                if (yxday5) yxsy = yxsy + zf;
                if (dtday5)   dtsy = dtsy + zf;
                sy6 = sy6 + zf;
                ljsy = ljsy + zf;
                if (isZt(buy)) zt6 ++;
                if ( Double.parseDouble(buy.getRatio().replace("%", "")) > Double.parseDouble(max6.replace("%", ""))) max6 = buy.getRatio();
                if ( Double.parseDouble(buy.getRatio().replace("%", "")) < Double.parseDouble(min6.replace("%", ""))) min6 = buy.getRatio();

                day1 = false;
                day2 = false;
                day3 = false;
                day4 = false;
                day5 = false;
                day6 = true;
                day7 = false;
            } else if (day6 && code.equals(buy.getCode())) {
                if (zf > 0) {
                    suc7 ++;
                    dtday7 = true;
                }else {
                    fai7 ++;
                    dtday7 = false;
                }
                if (Double.parseDouble(buy.getClose()) >= Double.parseDouble(buy.getOpen())) {
                    yxday7 = true;
                }
                if (yxday6) yxsy = yxsy + zf;
                if (dtday6)   dtsy = dtsy + zf;
                sy7 = sy7 + zf;
                ljsy = ljsy + zf;
                if (isZt(buy)) zt7 ++;
                if ( Double.parseDouble(buy.getRatio().replace("%", "")) > Double.parseDouble(max7.replace("%", ""))) max7 = buy.getRatio();
                if ( Double.parseDouble(buy.getRatio().replace("%", "")) < Double.parseDouble(min7.replace("%", ""))) min7 = buy.getRatio();

                day1 = false;
                day2 = false;
                day3 = false;
                day4 = false;
                day5 = false;
                day6 = false;
                day7 = true;
            }
        }
        if (count != null) log.info("统计标的数量：{}，日期区间：{} - {}", count, start, end);
        int zs1 = suc1 + fai1 == 0 ? 1 : suc1 + fai1;
        int zs2 = suc2 + fai2 == 0 ? 1 : suc2 + fai2;
        int zs3 = suc3 + fai3 == 0 ? 1 : suc3 + fai3;
        int zs4 = suc4 + fai4 == 0 ? 1 : suc4 + fai4;
        int zs5 = suc5 + fai5 == 0 ? 1 : suc5 + fai5;
        int zs6 = suc6 + fai6 == 0 ? 1 : suc6 + fai6;
        int zs7 = suc7 + fai7 == 0 ? 1 : suc7 + fai7;

        BigDecimal re1 = BigDecimal.valueOf((double) ((int) sy1 * 100 / zs1) / 100).setScale(2, RoundingMode.HALF_UP);
        BigDecimal re2 = BigDecimal.valueOf((double) ((int) sy2 * 100 / zs2) / 100).setScale(2, RoundingMode.HALF_UP);
        BigDecimal re3 = BigDecimal.valueOf((double) ((int) sy3 * 100 / zs3) / 100).setScale(2, RoundingMode.HALF_UP);
        BigDecimal re4 = BigDecimal.valueOf((double) ((int) sy4 * 100 / zs4) / 100).setScale(2, RoundingMode.HALF_UP);
        BigDecimal re5 = BigDecimal.valueOf((double) ((int) sy5 * 100 / zs5) / 100).setScale(2, RoundingMode.HALF_UP);
        BigDecimal re6 = BigDecimal.valueOf((double) ((int) sy6 * 100 / zs6) / 100).setScale(2, RoundingMode.HALF_UP);
        BigDecimal re7 = BigDecimal.valueOf((double) ((int) sy7 * 100 / zs7) / 100).setScale(2, RoundingMode.HALF_UP);
        log.info("买入首日统计结果，成功：{}次，失败：{}次，涨停：{}次，最大涨幅：{}，最小涨幅：{}，胜率：{}%，平均涨幅：{}%", suc1, fai1, zt1, max1, min1, (int)((double) suc1 * 1000/ zs1)/ 10, re1);
        log.info("买入次日统计结果，成功：{}次，失败：{}次，涨停：{}次，最大涨幅：{}，最小涨幅：{}，胜率：{}%，平均涨幅：{}%", suc2, fai2, zt2, max2, min2, (int)((double) suc2 * 1000/ zs2)/ 10, re2);
        log.info("买入三日统计结果，成功：{}次，失败：{}次，涨停：{}次，最大涨幅：{}，最小涨幅：{}，胜率：{}%，平均涨幅：{}%", suc3, fai3, zt3, max3, min3, (int)((double) suc3 * 1000/ zs3)/ 10, re3);
        log.info("买入四日统计结果，成功：{}次，失败：{}次，涨停：{}次，最大涨幅：{}，最小涨幅：{}，胜率：{}%，平均涨幅：{}%", suc4, fai4, zt4, max4, min4, (int)((double) suc4 * 1000/ zs4)/ 10, re4);
        log.info("买入五日统计结果，成功：{}次，失败：{}次，涨停：{}次，最大涨幅：{}，最小涨幅：{}，胜率：{}%，平均涨幅：{}%", suc5, fai5, zt5, max5, min5, (int)((double) suc5 * 1000/ zs5)/ 10, re5);
        log.info("买入六日统计结果，成功：{}次，失败：{}次，涨停：{}次，最大涨幅：{}，最小涨幅：{}，胜率：{}%，平均涨幅：{}%", suc6, fai6, zt6, max6, min6, (int)((double) suc6 * 1000/ zs6)/ 10, re6);
        log.info("买入七日统计结果，成功：{}次，失败：{}次，涨停：{}次，最大涨幅：{}，最小涨幅：{}，胜率：{}%，平均涨幅：{}%", suc7, fai7, zt7, max7, min7, (int)((double) suc7 * 1000/ zs7)/ 10, re7);

        log.info(" ");
        log.info("坚定持有一日平均涨幅：{}%", re1);
        log.info("坚定持有两日平均涨幅：{}%", re1.add(re2));
        log.info("坚定持有三日平均涨幅：{}%", re1.add(re2).add(re3));
        log.info("坚定持有四日平均涨幅：{}%", re1.add(re2).add(re3).add(re4));
        log.info("坚定持有五日平均涨幅：{}%", re1.add(re2).add(re3).add(re4).add(re5));
        log.info("坚定持有六日平均涨幅：{}%", re1.add(re2).add(re3).add(re4).add(re5).add(re6));
        log.info("坚定持有七日平均涨幅：{}%", re1.add(re2).add(re3).add(re4).add(re5).add(re6).add(re7));

        // 当前收入就逢高卖出
        log.info(" ");
        log.info("动态盈利持有累计涨幅：{}%", BigDecimal.valueOf(dtsy).setScale(2, RoundingMode.HALF_UP));
        log.info("动态阳线持有累计涨幅：{}%", BigDecimal.valueOf(yxsy).setScale(2, RoundingMode.HALF_UP));
        log.info("静态持有七天累计涨幅：{}%", BigDecimal.valueOf(ljsy).setScale(2, RoundingMode.HALF_UP));
    }

    /**
     * 是否放量
     * */
    private static Boolean isFl(History today, History yesterday, Double ratio){
        return Double.parseDouble(today.getTurnover()) > Double.parseDouble(yesterday.getTurnover()) * ratio;
    }

    /**
     * 是否缩量
     * */
    private static Boolean isSl(History today, History yesterday, Double ratio){
        return Double.parseDouble(today.getTurnover()) < Double.parseDouble(yesterday.getTurnover()) * ratio;
    }

    /**
     * 是否一字
     * */
    private static Boolean isYi(History today){
        return today.getClose().equals(today.getOpen());
    }

    /**
     * 是否涨停
     * */
    private static Boolean isZt(History today){
        return Double.parseDouble(today.getRatio().replace("%", "")) >= 9.8 && (today.getCode().startsWith("6") || today.getCode().startsWith("0")
                || Double.parseDouble(today.getRatio().replace("%", "")) >= 19.8 && today.getCode().startsWith("3"));
    }

    /**
     * 是否跌停
     * */
    private static Boolean isDt(History today){
        return Double.parseDouble(today.getRatio().replace("%", "")) <= -9.8 && (today.getCode().startsWith("6") || today.getCode().startsWith("0")
                || Double.parseDouble(today.getRatio().replace("%", "")) <= -19.8 && today.getCode().startsWith("3"));
    }

    private static Boolean isZt(Analysis today){
        return Double.parseDouble(today.getRatio().replace("%", "")) >= 9.8 && (today.getCode().startsWith("6") || today.getCode().startsWith("0")
                || Double.parseDouble(today.getRatio().replace("%", "")) >= 19.8 && today.getCode().startsWith("3"));
    }

    /**
     * 是否阴线
     * */
    private static Boolean isYx(History today){
        return Double.parseDouble(today.getClose()) < Double.parseDouble(today.getOpen());
    }

    /**
     * 是否低开
     * */
    private static Boolean isDk(History today, History yesterday){
        return Double.parseDouble(today.getOpen()) < Double.parseDouble(yesterday.getClose());
    }

    /**
     * 是否反包
     * */
    private static Boolean isFb(History today, Double ratio){
        return Double.parseDouble(today.getRatio().replace("%", "")) >= ratio;
    }

    /**
     * 是否冲高回落
     * */
    private static Boolean isCg(History today, Double ratio){
        return 100* (Double.parseDouble(today.getHigh()) - Double.parseDouble(today.getOpen()))/ Double.parseDouble(today.getOpen()) > Double.parseDouble(today.getRatio().replace("%", "")) * ratio;
    }

    /**
     * 连续三板后洗盘到首板顶部
     * @return true：当天尾盘或次日早盘买入
     * */
    private Boolean analysisModelB(History history, List<History> days, Integer limit) {
        if (days.size() == 0) {
            // 涨停前一天不能涨停
            if (isZt(history)) {
                days.add(history);
            } else {
                days.clear();
            }
            return false;
        }
        if (days.size() == 1) {
            // 涨停前一天不能涨停
            if (isZt(history)) {
                days.add(history);
            } else {
                days.clear();
            }
            return false;
        }
        if (days.size() == 2) {
            // 涨停前一天不能涨停
            if (isZt(history)) {
                days.add(history);
            } else {
                days.clear();
            }
            return false;
        }
        History firstDay = days.get(0); // 首板

        if (isDt(history)) {
            days.clear();
            return false;
        }

        if (Double.parseDouble(history.getClose()) <= Double.parseDouble(firstDay.getClose()) * 1.03
                && Double.parseDouble(history.getClose()) >= Double.parseDouble(firstDay.getClose()) * 0.97){
            days.clear();
            return true;
        } else if (days.size() < (limit - 1)){
            days.add(history);
            return false;
        } else {
            days.clear();
            return false;
        }
    }

    /**
     * 横盘后缩量单板后几天内洗盘上车模型
     * @return true：当天尾盘或次日早盘买入
     * */
    private Boolean analysisModel(History history, List<History> days, Integer limit) {
        // 放量比例
        double flRatio = 2;
        double slRatio = 3;
        // 换手率
        double hsRatio = 3;
        // day0：非涨停
        // day1：涨停，非一字，不放量
        // day2：放量下跌
        // day3：低开，收盘反包day2收盘价，则day4早盘买入，
        // day3：低开，收盘未反包day2收盘价，则不操作
        // day4：参考day3
        // day5：参考day4

        // 买入当天亏钱，第二天开盘卖出
        // 买入当天赚钱，第二天继续持有，尾盘亏钱卖出


        if (days.size() == 0) {
            // 涨停前一天不能涨停
            if (!isZt(history)) {
                days.add(history);
            }
            return false;
        }
        if (days.size() == 1) {
            //  涨停第一天，需要首板，需要缩量，不能是一字
            if (isZt(history) && !isYi(history)) {
                days.add(history);
            } else {
                days.clear();
                days.add(history);
            }
            return false;
        }

        History yesterday = days.get(days.size() - 1); // 上一日
        if (days.size() == 2) {
            // 涨停第二天需要放量阴线
            if (isYx(history) && isFl(history, yesterday, flRatio)) {
                days.add(history);
            } else {
                days.clear();
            }
            return false;
        }

        History ztDay = days.get(1); // 涨停日
        History flDay = days.get(2); // 放量日

//        // 持续缩量
//        if (isFl(history, days.get(days.size() - 1), 1.2)) {
//            days.clear();
//            return false;
//        }

        // 反包0.5到3个点，并且量小于放量那天的1/3以下
        if (isFb(history, 0.5) && !isFb(history, 3.0) &&
        isSl(history, flDay, 0.3)) {
            // 收盘价大于涨停日的收盘价，继续后看
            if (Double.parseDouble(history.getClose()) > Double.parseDouble(ztDay.getClose())) {
                days.add(history);
                return false;
            }

            // 收盘价小于涨停日的开盘价，继续后看
            if (Double.parseDouble(history.getClose()) < Double.parseDouble(ztDay.getOpen())) {
                days.add(history);
                return false;
            }

            days.clear();
            return true;
        } else if(!isFb(history, 3.0) && days.size() < (limit - 1)){
            // 下跌或量不够缩，继续后看
            days.add(history);
        } else {
            // 大涨，不看了
            days.clear();
        }
        return false;
    }
}
